/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jxtaEssentials;

import net.jxta.discovery.DiscoveryEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jxta.discovery.DiscoveryListener;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.AdvertisementFactory;
import net.jxta.id.ID;
import net.jxta.id.IDFactory;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.pipe.PipeID;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.socket.JxtaServerSocket;
import net.jxta.socket.JxtaSocket;
import java.io.PrintWriter;

/**
 *
 * @author Asistente
 */
public class BigManager implements DiscoveryListener {
    //Es el ID usado para el pipe. Estos IDs pueden ser generados usando el metodo newPipeID de la clase IDFactory de JXTA

    public final static String SOCKET_ID = "urn:jxta:uuid-59616261646162614E5047205032503393B5C2F6CA7A41FBB0F890173088E79404";
    private JxtaServerSocket mySocketPipe;
    PeerGroup netPeerGroup;
    PipeAdvertisement pipeAdv;
    private static final Logger LOG =
            Logger.getLogger(BigManager.class.getName());
    DiscoveryService discovery;
    private static BigManager INSTANCE = null;

    public static BigManager getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new BigManager();
        }
        return INSTANCE;

    }

    public BigManager() {
        //Inicializa Jxta
        NetworkManager manager = null;
        try {
            manager = new NetworkManager(NetworkManager.ConfigMode.ADHOC, "FileSharing",
                    new File(new File(".cache"), "FileSharing").toURI());
            manager.startNetwork();
        } catch (Exception ex) {
            Logger.getLogger(BigManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        //Registra el advertisement
        AdvertisementFactory.registerAdvertisementInstance(FileAdvertisement.getAdvertisementType(),
                new FileAdvertisement.Instantiator());

        //Inicializa los servicios
        netPeerGroup = manager.getNetPeerGroup();
        discovery = netPeerGroup.getDiscoveryService();
       //Crea y publica un pipe advertisement
        PeerGroupID id = netPeerGroup.getPeerGroupID();
        PipeID idPipe = createNewPipeID(id);
        pipeAdv = createPipeAdvertisement(idPipe);
        System.out.println("Id del Pipe: " + pipeAdv.getID().toString());

        //Crea el server socket por el cual va a recibir conexiones
        try {
            mySocketPipe = new JxtaServerSocket(netPeerGroup, pipeAdv);
        } catch (Exception ex) {
            Logger.getLogger(BigManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void newFileAdvertisement(String... args) {
//        AdvertisementFactory.registerAdvertisementInstance(
//            FileAdvertisement.getAdvertisementType(),
//        new FileAdvertisement.Instantiator());
        FileAdvertisement advFile = new FileAdvertisement();
        advFile.setID(ID.nullID);

        advFile.setFileName(args[0]);
        advFile.setPipeAdv(pipeAdv);
        try {
            discovery.publish(advFile);
            System.out.println(advFile.toString());
        } catch (IOException ex) {
            System.err.println("Error al crear el advertisement");
            Logger.getLogger(BigManager.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private static PipeID createNewPipeID(PeerGroupID pgID) {
        PipeID socketID = null;

        try {
            socketID = (PipeID) IDFactory.fromURI(new URI(SOCKET_ID));
        } catch (URISyntaxException ex) {
        }
        return socketID;
    }

    private PipeAdvertisement createPipeAdvertisement(ID pipeId) {

        PipeAdvertisement advertisement = (PipeAdvertisement) AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());

        advertisement.setPipeID(pipeId);
        advertisement.setType(PipeService.UnicastType);
        advertisement.setName("Pipe comunicacion");
        return advertisement;
    }

    public void searchByFileName(String name, int num) {
        //discovery.addDiscoveryListener(this);
        System.out.println("Buscar advertisements");
        discovery.getRemoteAdvertisements(
                null, // no specific peer (propagate)
                DiscoveryService.ADV, // Adv type
                FileAdvertisement.fileNameTag, // Attribute = nombreAdvertisement
                "*" + name + "*", // busca advertisements que contengan el valor de name
                num, // numero de advertisements que va a buscar
                this);//El listener
//        try {
//            Thread.sleep(20000);
//        } catch (InterruptedException ex) {
//            Logger.getLogger(BigManager.class.getName()).log(Level.SEVERE, null, ex);
//        }

    }

    public void discoveryEvent(DiscoveryEvent de) {
        System.out.println("Encontro advertisements");
        Enumeration<Advertisement> respuestas = de.getSearchResults();
        while (respuestas.hasMoreElements()) {

            Object advertTemp = respuestas.nextElement();
            if (advertTemp instanceof FileAdvertisement) {

                FileAdvertisement fileAdvertisement = (FileAdvertisement) advertTemp;
                String nombre = fileAdvertisement.getFileName();

                if (nombre != null) {
                    System.out.println("Nombre del archivo: " + nombre);
                    PipeAdvertisement pAdv = fileAdvertisement.getPipeAdv();
                    System.out.println("Id del Pipe encontrado: " + fileAdvertisement.getID());
                    enviarMensaje(pAdv);
                }
            }
        }
    }

    public void enviarMensaje(PipeAdvertisement pipeAdv) {
        try {
            JxtaSocket socket = new JxtaSocket(netPeerGroup, pipeAdv);

            PrintWriter out = new PrintWriter(socket.getOutputStream());
            out.println("Hola publicador");

            out.close();
            socket.close();
        } catch (IOException ex) {
            System.out.println("El advertisement ha expirado");
        }
    }

    public void waitForFile() {

        try {
            JxtaSocket socket = (JxtaSocket) mySocketPipe.accept();
            System.out.println("Acepto una conexion");
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            System.out.println(input.readLine());

            input.close();
            socket.close();
        } catch (Exception ex) {
            System.out.println("Error al conectarse");
        }
    }

    public void createAdvertisements(File dir) {
        // The list of files can also be retrieved as File objects
        File[] files = dir.listFiles();

// This filter only returns directories
        FileFilter fileFilter = new FileFilter()   {

            public boolean accept(File file) {
                return file.isFile();
            }
        };

        files = dir.listFiles(fileFilter);
        if (files == null) {
            System.out.println("No Existe ningun archivo en: " + dir.toString());
        } else {
            for (int i = 0; i < files.length; i++) {
                // Get filename of file or directory
                File file = files[i];
                System.out.println("Creando Advertisement #" + i + ": " + file.getName());
                newFileAdvertisement(file.getName());
            }
        }

    }
}
